import { Injectable } from "@angular/core";
import * as d3 from "d3";

@Injectable({
  providedIn: "root",
})
export class VisualService {
  constructor() {}
  public icdMode: string = "All"; //icdCode,icdName
  public getFishbone(rl: any[]): fishboneData {
    let data = new fishboneData();
    rl.forEach((r) => {
      data.mrid = r["MRID"];
      data.name = r["Name"];
      data.birthday = new Date(r["Birthday"]);
      if (r["DischargePathCode"] == "5") {
        data.deathday = new Date(r["DischargeDateTime"]);
      }
      let inp = new inpatient();
      inp.begin = new Date(r["AdmissionDateTime"]);
      inp.end = new Date(r["DischargeDateTime"]);
      r["Diagnosis"].forEach((element) => {
        let t = new diagnosis();
        t.catalog = "Discharge";
        t.icd = element["DiagnosisICDCode"];
        t.icdName = element["DiagnosisICDName"];
        t.internalIcd = element["InternalICDCode"];
        t.internalIcdName = element["InternalICDName"];
        t.order = element["DiagnosisOrder"];
        t.curative = element["DischargeState"];
        inp.diagnosises.push(t);
      });
      // r["VAllergyDiagnosis"].forEach((element) => {
      //   let t = new diagnosis();
      //   t.catalog = "VAllergyDiagnosis";
      //   t.icd = element["DiagnosisICDCode"];
      //   t.icdName = element["DiagnosisICDName"];
      //   t.internalIcd = element["InternalICDCode"];
      //   t.internalIcdName = element["InternalICDName"];
      //   t.order = element["DiagnosisOrder"];
      //   t.curative = element["DischargeState"];
      //   inp.diagnosises.push(t);
      // });
      // r["VClinicDiagnosis"].forEach((element) => {
      //   let t = new diagnosis();
      //   t.catalog = "VClinicDiagnosis";
      //   t.icd = element["DiagnosisICDCode"];
      //   t.icdName = element["DiagnosisICDName"];
      //   t.internalIcd = element["InternalICDCode"];
      //   t.internalIcdName = element["InternalICDName"];
      //   t.order = element["DiagnosisOrder"];
      //   t.curative = element["DischargeState"];
      //   inp.diagnosises.push(t);
      // });
      r["VOperate"].forEach((element) => {
        let t = new operation();
        t.catalog = "VOperate";
        t.icd = element["OperateICDCode"];
        t.icdName = element["OperateICDName"];
        t.internalIcd = element["InternalICDCode"];
        t.internalIcdName = element["InternalICDName"];
        t.order = element["OperateOrder"];
        t.grade = Number(element["OperateLevelCode"]);
        inp.operations.push(t);
      });
      r["VSurgery"].forEach((element) => {
        let t = new operation();
        t.catalog = "VSurgery";
        t.icd = element["OperateICDCode"];
        t.icdName = element["OperateICDName"];
        t.internalIcd = element["InternalICDCode"];
        t.internalIcdName = element["InternalICDName"];
        t.order = element["OperateOrder"];
        t.grade = Number(element["OperateLevelCode"]);
        inp.operations.push(t);
      });
      data.inpatientTrace.push(inp);
    });

    return data;
  }
  public drawSpineLine(canvas): void {
    let svg = d3.select(canvas);
    const height = +svg.attr("height");
    const width = +svg.attr("width");

    svg
      .append("line")
      .attr("x1", 0)
      .attr("y1", height / 2)
      .attr("x2", width)
      .attr("y2", height / 2)
      .attr("stroke", "black")
      .attr("stroke-width", "2px");
  }
  deltax = 30;
  public drawRibLine(canvas, startx, ribheight): void {
    let svg = d3.select(canvas);
    const height = +svg.attr("height");
    const width = +svg.attr("width");

    svg
      .append("line")
      .attr("x1", startx)
      .attr("y1", height / 2)
      .attr("x2", startx - this.deltax)
      .attr("y2", height / 2 + ribheight)
      .attr("stroke", "black")
      .attr("stroke-width", "0.2px");
  }
  public drawStartPoint(canvas): void {
    let svg = d3.select(canvas);
    const height = +svg.attr("height");
    const width = +svg.attr("width");

    svg
      .append("circle")
      .attr("cx", 5)
      .attr("cy", height / 2)
      .attr("r", 5);
  }
  public drawEndPoint(canvas): void {
    let svg = d3.select(canvas);
    const height = +svg.attr("height");
    const width = +svg.attr("width");

    svg
      .append("line")
      .attr("x1", width)
      .attr("y1", height / 2)
      .attr("x2", width - 10)
      .attr("y2", height / 2 - 10)
      .attr("stroke", "black")
      .attr("stroke-width", "2px");

    svg
      .append("line")
      .attr("x1", width)
      .attr("y1", height / 2)
      .attr("x2", width - 10)
      .attr("y2", height / 2 + 10)
      .attr("stroke", "black")
      .attr("stroke-width", "2px");
  }
  public drawRibText(canvas, startx, ribheight, text) {
    let svg = d3.select(canvas);
    const height = +svg.attr("height");
    const width = +svg.attr("width");
    svg
      .append("text")
      .attr("x", startx - this.deltax)
      .attr("y", height / 2 + ribheight)
      .attr("font-size", 8)
      .text(text)
      .attr("stroke", "black")
      .attr("stroke-width", "0.5px");
  }
  public drawEndText(canvas, text) {
    let svg = d3.select(canvas);
    const height = +svg.attr("height");
    const width = +svg.attr("width");
    svg
      .append("text")
      .attr("x", width - 200)
      .attr("y", height / 2 + 20)

      .text(text)
      .attr("stroke", "black")
      .attr("stroke-width", "1px");
  }
  public drawStartText(canvas, text) {
    let svg = d3.select(canvas);
    const height = +svg.attr("height");
    const width = +svg.attr("width");
    svg
      .append("text")
      .attr("x", 0)
      .attr("y", height / 2 + 20)

      .text(text)
      .attr("stroke", "black")
      .attr("stroke-width", "1px");
  }
  getAbsoluteX(time, start, end, width, marginLeft, marginRight) {
    console.log(end);
    console.log(typeof end);
    let percent =
      Number(time.getTime() - start.getTime()) /
      Number(end.getTime() - start.getTime());
    let x = (width - marginLeft - marginRight) * percent + marginLeft;
    return x;
  }

  activezoom(canvas) {
    let svg = d3.select(canvas);
    let height = svg.attr("height");
    let width = svg.attr("width");
    svg.call(
      d3
        .zoom()
        .extent([
          [0, 0],
          [width, height],
        ])
        .scaleExtent([1, 8])
        .on("zoom", zoomed)
    );

    function zoomed() {
      svg.attr("transform", d3.event.transform);
    }
    //this.zoom = d3.zoom().scaleExtent([1, 8]).on("zoom", this.zoomed(svg));
  }

  public drawFishbone(canvas, results, expand) {
    let svg = d3.select(canvas);

    const height = +svg.attr("height");
    const width = +svg.attr("width");
    svg.selectAll("svg > *").remove();
    // svg.remove();
    // svg.append("svg");
    let data = this.getFishbone(results);
    console.log(data);

    this.activezoom(canvas);

    this.drawSpineLine("svg");
    this.drawStartPoint("svg");
    this.drawEndPoint("svg");
    this.drawEndText("svg", data.getEndDay());
    this.drawStartText("svg", data.birthday);

    var min, max;
    // data.inpatientTrace.map((v) => (min = Math.min(v.begin.getTime(), min)));
    // data.inpatientTrace.map((v) => (max = Math.max(v.begin.getTime(), max)));
    max = Math.max.apply(
      Math,
      data.inpatientTrace.map(function (o) {
        return o.begin.getTime();
      })
    );
    min = Math.min.apply(
      Math,
      data.inpatientTrace.map(function (o) {
        return o.begin.getTime();
      })
    );
    data.inpatientTrace.forEach((ip) => {
      var s = data.birthday;
      var e = data.deathday;
      if (e === undefined) e = new Date();
      if (expand) {
        s = new Date(min);
        e = new Date(max);
      }
      var sp = this.getAbsoluteX(ip.begin, s, e, width, 50, 30);

      this.drawRibLine("svg", sp, -120);
      let textdelte = this.deltax / ip.diagnosises.length;
      let textheight = 120 / ip.diagnosises.length;
      var i = 0;

      ip.diagnosises.forEach((diagnosis) => {
        let signText = diagnosis.icdName + "(" + diagnosis.icd + ")";
        if (this.icdMode === "icdCode") signText = diagnosis.icd;
        if (this.icdMode === "icdName") signText = diagnosis.icdName;
        this.drawRibText(
          "svg",
          sp - this.deltax + i * textdelte,
          -120 + textheight * i,
          signText
        );
        i++;
      });
      this.drawRibLine("svg", sp, 120);
      i = 0;
      ip.operations.forEach((op) => {
        let signText = op.icdName + "(" + op.icd + ")";
        if (this.icdMode === "icdCode") signText = op.icd;
        if (this.icdMode === "icdName") signText = op.icdName;
        this.drawRibText(
          "svg",
          sp - this.deltax + i * textdelte,
          120 - textheight * i,
          signText
        );
        i++;
      });
    });
  }
}
export class diagnosis {
  public icdName: string;
  public icd: string;
  public internalIcd: string;
  public internalIcdName: string;
  public order: number;
  public catalog: string;
  public curative: string;
}
export class operation {
  public icdName: string;
  public icd: string;
  public internalIcd: string;
  public internalIcdName: string;
  public order: number;
  public catalog: string;
  public grade: number;
}
export class inpatient {
  public begin: Date;
  public end: Date;
  public diagnosises: diagnosis[];
  public operations: operation[];
  constructor() {
    this.diagnosises = [];
    this.operations = [];
  }
  public begintime(birthday: Date): number {
    if (birthday === undefined) return 0;
    if (this.begin === undefined) return 0;
    console.log(this.begin);
    return this.begin.getTime() - birthday.getTime();
  }
  public endtime(birthday: Date): number {
    if (birthday === undefined) return 0;
    if (this.end === undefined) return 0;
    return this.end.getTime() - birthday.getTime();
  }
}
export class fishboneData {
  public mrid: string;
  public name: string;
  public birthday: Date;
  public deathday: Date;
  public grnder: string;
  public inpatientTrace: inpatient[];
  constructor() {
    this.mrid = "";
    this.name = "";
    this.birthday = undefined;
    this.deathday = undefined;
    this.grnder = undefined;
    this.inpatientTrace = [];
  }

  public lifetime(): number {
    if (this.birthday === undefined) return 0;
    var ed = this.deathday;
    if (ed === undefined) ed = new Date();
    let rv = Number(ed.getTime()) - Number(this.birthday.getTime());
    return rv;
  }
  public getEndDay() {
    if (this.deathday === undefined) return Date();
    return this.deathday;
  }
}
